#define _CRT_SECURE_NO_WARNINGS 1

// 命名空间

//#include <stdio.h>
//#include <stdlib.h>
//
//int rand = 0; // 编译的时候cstdlib全局展开，与rand发生命名冲突
//// 也就是说，我们和库之间会有命名冲突
//// 而在公司里面，一个项目有好多人，很有可能会有命名冲突
//
//int main()
//{
//	printf("%d\n", rand);
//
//	return 0;
//}

// 于是，为了解决命名冲突的问题，就有了命名空间
// 关键字namespace

//#include <stdio.h>
//#include <stdlib.h>
//
// // 本质上是定义一个命名空间域
//namespace tan
//{
//	 // 命名空间中可以定义变量/函数/类型
//	int rand = 0;
//
//	int Add(int left, int right)
//	{
//		return left + right;
//	}
//
//	struct Node
//	{
//		struct Node* next;
//		int val;
//	};
//
//}
//
//int a = 0;

// 编译的时候，默认的查找顺序是局部 -> 全局
// 不会到命名空间里面找，至少默认情况下是这样的
// 就像我们去外面采蔬菜，先看你家的自留地有没有菜，这就是局部优先原则
// 如果自留地没有，就去村子野地去找，有就摘，这就是全局
// 而命名空间就像别人家的自留地，在没有别人的允许下是不能摘的，不然就是偷菜

//int main()
//{
//	printf("%p\n", rand); // 随机值，取到的是库里面的，是指针
//	printf("%d\n", tan::rand); // 访问的就是tan命名空间域
//
//	int a = 1;
//	printf("%d\n", a);
//	printf("%d\n", ::a); // ::域限定符，左边没加默认全局
//
//	struct tan::Node pnode; // 在结构体的名字前面包
//
//	return 0;
//}	

// 命名空间可以嵌套
//2. 命名空间可以嵌套
// test.cpp
//namespace N1
//{
//	int a;
//	int b;
//	int Add(int left, int right)
//	{
//		return left + right;
//	}
//	namespace N2
//	{
//		int c;
//		int d;
//		int Sub(int left, int right)
//		{
//			return left - right;
//		}
//	}
//}
//
//// test.h
//namespace N1
//{
//	int Mul(int left, int right)
//	{
//		return left * right;
//	}
//}
// 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
// ps：一个工程中的test.h和上面test.cpp中两个N1会被合并成一个
// 注意：一个命名空间就定义了一个新的作用域，命名空间中的所有内容都局限于该命名空间中

// 使用命名空间
//#include <stdio.h>
//#include <stdlib.h>

// 有没有什么方式可以在不重名的前提下不指定域呢？
// 展开命名空间 using namespace tan; 
// 展开命名空间就像是在自己的自留地上插了一块牌子，上面写着“我家菜多，需要自取”

// 局部 -> 全局 -> 展开的命名空间
// 不同域可以同名，不同自留地都有葱，想摘的时候还是可以很明确的知道采哪里
// 基本上不存在冲突，很智能
// 但是如果两个命名空间都展开了，就会出问题了
// 摘葱，张大爷和王大爷都让摘，你这时候就纠结了，就是这个道理
// 要认识到展开命名空间也是有坏处的

// 单独展开可以直接
// using tan::Add;

// 三种
// 1.指定访问
// 2.全展开
// 3.指定展开某一个

// 总结一下，命名空间本质上是定义一个域，可以做到名字的隔离
// 不同域可以定义同名的变量/函数/类型

// 输入输出
// cout console output

//#include <iostream> // 没有后缀.h了
//// C++也封装了之前C语言的一些带.h后缀的头文件，改为类似于cstdio
//// using namespace std; // 或者直接把标准库全展开
//
//int main()
//{
//	int i = 0;
//	double j = 1.11;
//
//	// 特点是自动识别类型，但是这样是编译不过的
//	// 会找不到，显示cout endl是未定义的
//	// C++的标准库为了防止它定义的东西跟你的冲突了
//	// 把它的东西包在了一个叫做std的命名空间
//
//	// cout << i << " " << j << endl; // err
//	std::cout << i << " " << j << std::endl;
//	/*using std::cout;
//	using std::endl;*/
//
//	// 流提取
//	// using std::cin;
//	// cin >> i >> j; // 不需要取地址了
//	// 一开始随便玩，不习惯这个用scanf、printf也行
//	// 后期基本上就切换到cout、cin了
//	// printf、scanf会更高效一点，只是绝大部分关系不大
//
//	return 0;
//}

// 缺省参数
// 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。
// 在调用该函数时，如果没有指定实参则采用该形参的缺省值，否则使用指定的实参。

//#include <iostream>
//using namespace std;
//
//void Func1(int a = 0)
//{
//	cout << a << endl;
//}
//
//// 全缺省
//void Func2(int a = 10, int b = 20, int c = 30)
//{
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl;
//}
//
//// 半缺省
//// 半缺省参数必须从右往左依次来给出
//void Func3(int a, int b = 20, int c = 30)
//{
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl;
//}
//
//int main()
//{
//	Func1(); // 0
//	Func1(2); // 2
//
//	// 必须按顺序传递，不能跳跃着传
//	// 缺省值必须是常量或者全局变量
//	Func2(1, 2, 3);
//	Func2(1, 2);
//	Func2(1);
//	Func2();
//
//	Func3(6); // 至少得传一个
//
//	return 0;
//}

// 缺省参数的使用场景
// 缺省参数不能声明和定义同时给

// 比如说万一声明给4，定义给10，就比较尴尬，实际上以声明为主
























